#include "system/thread.h"

namespace dw {
	namespace system {

//------------------------------------------------------------------------------
// Construction & destruction
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Thread::Thread(const char* name, bool start /* = true */)
:	_handle(NULL)
,	_id(-1)
,	_priority(TP_Default)
,	_state(TS_Invalid)
{
	create(start);
}

//------------------------------------------------------------------------------
Thread::~Thread()
{
	wait();
}

//------------------------------------------------------------------------------
// Commands
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void Thread::start()
{
	dwAssert(_handle != NULL, "Invalid internal state");
	dwAssert(_state == TS_Created, "Invalid internal state");
	
	if (::ResumeThread(_handle) == -1)
	{
		dwFail("Failed to start thread");
		_state = TS_Invalid;
	}
	else
	{
		_state = TS_Running;
	}
}

//------------------------------------------------------------------------------
bool Thread::wait(int32 timeOut /* = WaitInfinite */)
{
	dwAssert(_handle != NULL, "Invalid internal state");
	dwAssert(_state == TS_Running, "Invalid internal state");

	BOOL result = FALSE;

	if (::WaitForSingleObject(_handle, timeOut) == WAIT_OBJECT_0)
	{
		result = ::CloseHandle(_handle);
		dwAssert(result == TRUE, "CloseHandle failed");

		_handle = NULL;
		_state = TS_Terminated;
	}

	return result == TRUE;
}

//------------------------------------------------------------------------------
void Thread::suspend()
{
	dwAssert(_handle != NULL, "Invalid internal state");
	dwAssert(_state == TS_Running, "Invalid internal state");

	if (::SuspendThread(_handle) == -1)
	{
		dwFail("Failed to suspend thread");
		_state = TS_Invalid;
	}
	else
	{
		_state = TS_Suspended;
	}
}

//------------------------------------------------------------------------------
void Thread::resume()
{
	dwAssert(_handle != NULL, "Invalid internal state");
	dwAssert(_state == TS_Suspended, "Invalid internal state");

	if (::ResumeThread(_handle) == -1)
	{
		dwFail("Failed to resume thread");
		_state = TS_Invalid;
	}
	else
	{
		_state = TS_Running;
	}
}

//------------------------------------------------------------------------------
void Thread::kill()
{
	dwAssert(_handle != NULL, "Invalid internal state");
	dwAssert(_state == TS_Created, "Invalid internal state");

	if (::TerminateThread(_handle, 0) == FALSE)
	{
		dwFail("Failed to kill thread");
		_state = TS_Invalid;
	}
	else
	{
		_state = TS_Terminated;
	}
}

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void Thread::create(bool start)
{
	_handle = ::CreateThread(NULL, 0, threadEntryPoint, this, start ? 0 : CREATE_SUSPENDED, &_id);

	if (_handle == NULL)
	{
		dwFail("Failed to create thread");
		_state = TS_Invalid;
	}
	else
	{
		_state = TS_Created;
	}
}

//------------------------------------------------------------------------------
void Thread::destroy()
{
	if (!wait(1000))
	{
		kill();
	}
}


//------------------------------------------------------------------------------
/*static*/ DWORD WINAPI Thread::threadEntryPoint(LPVOID parameter)
{
	dwAssert(parameter != NULL, "Invalid parameter");

	return reinterpret_cast< Thread* >(parameter)->run();
}

	} // namespace system
} // namespace dw
